<template>
  <div class="form-renderer" v-if="formDef">
    <h3>{{ formDef.name }}</h3>
    <el-form :model="currentFormData" ref="elFormRef" :label-width="0">
      <!-- No global label width -->
      <template v-if="isCollection && Array.isArray(currentFormData)">
        <div
          v-for="(dataItem, itemIndex) in currentFormData"
          :key="`data_item_${itemIndex}`"
          class="form-data-item"
        >
          <h4>
            {{ formDef.dataMetaModel?.name || '数据项' }} #{{ itemIndex + 1 }}
          </h4>
          <table class="rendered-table">
            <colgroup>
              <col
                v-for="(col, index) in formDef.gridDefinition.cols"
                :key="`col-def-${index}`"
                :style="{ width: `${col.width}px` }"
              />
            </colgroup>
            <tbody>
              <tr
                v-for="(rowDef, rIndex) in formDef.gridDefinition.rows"
                :key="`row-${itemIndex}-${rIndex}`"
                :style="{
                  height: `${rowDef.height}px`,
                  ...getRowStyle(rowDef),
                }"
              >
                <template
                  v-for="cellDef in getRenderableCellsInRow(rIndex)"
                  :key="`cell-${itemIndex}-${cellDef.key}`"
                >
                  <td
                    :style="getCellStyle(cellDef)"
                    :colspan="cellDef.colSpan"
                    :rowspan="cellDef.rowSpan"
                  >
                    <el-form-item
                      v-if="cellDef.content?.type === 'input'"
                      :prop="`${itemIndex}.${(cellDef.content as InputContent).prop}`"
                      :rules="getInputValidationRules(cellDef.content as InputContent)"
                      class="rendered-form-item"
                    >
                      <RenderCellContent
                        :content-def="cellDef.content!"
                        :data-value="resolveDataValue(cellDef, dataItem)"
                        v-model="dataItem[(cellDef.content as InputContent).prop]"
                      />
                    </el-form-item>
                    <RenderCellContent
                      v-else-if="cellDef.content"
                      :content-def="cellDef.content"
                      :data-value="resolveDataValue(cellDef, dataItem)"
                    />
                    <span v-else> </span>
                    <!-- Empty cell -->
                  </td>
                </template>
              </tr>
            </tbody>
          </table>
        </div>
      </template>
      <template v-else-if="!isCollection && currentFormData">
        <table class="rendered-table">
          <colgroup>
            <col
              v-for="(col, index) in formDef.gridDefinition.cols"
              :key="`col-def-${index}`"
              :style="{ width: `${col.width}px` }"
            />
          </colgroup>
          <tbody>
            <tr
              v-for="(rowDef, rIndex) in formDef.gridDefinition.rows"
              :key="`row-${rIndex}`"
              :style="{ height: `${rowDef.height}px`, ...getRowStyle(rowDef) }"
            >
              <template
                v-for="cellDef in getRenderableCellsInRow(rIndex)"
                :key="`cell-${cellDef.key}`"
              >
                <td
                  :style="getCellStyle(cellDef)"
                  :colspan="cellDef.colSpan"
                  :rowspan="cellDef.rowSpan"
                >
                  <el-form-item
                    v-if="cellDef.content?.type === 'input'"
                    :prop="(cellDef.content as InputContent).prop"
                    :rules="getInputValidationRules(cellDef.content as InputContent)"
                    class="rendered-form-item"
                  >
                    <RenderCellContent
                      :content-def="cellDef.content!"
                      :data-value="resolveDataValue(cellDef, currentFormData as Record<string, any>)"
                      v-model="(currentFormData as Record<string, any>)[(cellDef.content as InputContent).prop]"
                    />
                  </el-form-item>
                  <RenderCellContent
                    v-else-if="cellDef.content"
                    :content-def="cellDef.content"
                    :data-value="resolveDataValue(cellDef, currentFormData as Record<string, any>)"
                  />
                  <span v-else> </span>
                  <!-- Empty cell -->
                </td>
              </template>
            </tr>
          </tbody>
        </table>
      </template>
      <div v-else-if="!currentFormData && formDef.dataMetaModel">
        <p>等待加载 "{{ formDef.dataMetaModel.name }}" 数据...</p>
      </div>
      <div v-else-if="!formDef.dataMetaModel">
        <p>表单定义未关联数据元模型。</p>
      </div>
    </el-form>
  </div>
  <div v-else>
    <p>请提供表单定义 (formDef)。</p>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, PropType, computed, StyleValue, toRefs } from 'vue';
import type { FormInstance, FormItemRule } from 'element-plus';
import { FormDefinition } from '@/models/form.model';
import { CellDefinition } from '@/models/cell.model';
import { RowDefinition } from '@/models/row-column.model';
import { InputContent } from '@/models/content.model';
import RenderCellContent from './RenderCellContent.vue';

const props = defineProps({
  formDef: { type: Object as PropType<FormDefinition | null>, default: null },
  /**
   * The actual data to render.
   * Can be an object or an array of objects if formDef.dataMetaModel.isCollection is true.
   */
  formData: {
    type: [Object, Array] as PropType<
      Record<string, unknown> | Record<string, unknown>[] | null
    >,
    default: null,
  },
});

const elFormRef = ref<FormInstance>();
const { formDef, formData } = toRefs(props);

// Internal reactive copy of formData to allow modification by v-model
const currentFormData = ref<
  Record<string, unknown> | Record<string, unknown>[] | null
>(null);

watch(
  formData,
  (newData) => {
    // Deep copy to avoid modifying original prop data directly, and ensure reactivity
    currentFormData.value = JSON.parse(
      JSON.stringify(
        newData || (formDef.value?.dataMetaModel?.isCollection ? [] : {})
      )
    );
  },
  { immediate: true, deep: true }
);

const isCollection = computed(
  () => formDef.value?.dataMetaModel?.isCollection === true
);

function getRenderableCellsInRow(rowIndex: number): CellDefinition[] {
  if (!formDef.value) return [];
  const rowCells: CellDefinition[] = [];
  for (let j = 0; j < formDef.value.gridDefinition.colCount; j++) {
    const cell = formDef.value.gridDefinition.getCell(rowIndex, j);
    if (cell && !cell.isMergedSlave) {
      rowCells.push(cell);
    }
  }
  return rowCells;
}

function getCellStyle(cellDef: CellDefinition): StyleValue {
  const styleFromDef = { ...cellDef.style }; // Base style from cell definition
  // Horizontal alignment from cell style, vertical from cell style or row style
  const finalStyle: StyleValue = {
    backgroundColor: styleFromDef.backgroundColor,
    color: styleFromDef.color,
    fontSize: styleFromDef.fontSize,
    fontWeight: styleFromDef.fontWeight,
    textAlign: styleFromDef.textAlign || 'left', // Default to left if not set
    verticalAlign: styleFromDef.verticalAlign || 'top', // Default to top
    // TODO: Consider row/column level styles as fallbacks
  };
  if (cellDef.width) finalStyle.width = `${cellDef.width}px`; // Cell width override
  if (cellDef.height) finalStyle.height = `${cellDef.height}px`; // Cell height override
  return finalStyle;
}

function getRowStyle(rowDef: RowDefinition): StyleValue {
  return { ...rowDef.style }; // Apply row-level styles if any
}

function resolveDataValue(
  cellDef: CellDefinition,
  dataItem: Record<string, unknown> | null
): unknown {
  if (!dataItem || !cellDef.dataMetaModelField) {
    return undefined;
  }
  // Simple field access, for nested fields like 'user.name', this would need a helper
  return dataItem[cellDef.dataMetaModelField];
}

function getInputValidationRules(inputContent: InputContent): FormItemRule[] {
  const rules: FormItemRule[] = [];
  if (inputContent.required) {
    rules.push({
      required: true,
      message: `${inputContent.prop || '此项'}不能为空`,
      trigger: ['blur', 'change'],
    });
  }
  if (inputContent.inputType === 'number') {
    rules.push({
      type: 'number',
      message: '请输入数字',
      trigger: ['blur', 'change'],
    });
  }
  // Add more rules based on minLength, maxLength, specific patterns etc.
  return rules;
}

// Expose a method to validate the form
const validateForm = async () => {
  if (!elFormRef.value) return false;
  try {
    await elFormRef.value.validate();
    return true;
  } catch {
    return false;
  }
};

// Expose a method to get current form data
const getFormData = () => {
  return JSON.parse(JSON.stringify(currentFormData.value)); // Return a deep copy
};

defineExpose({
  validateForm,
  getFormData,
  resetForm: () => elFormRef.value?.resetFields(),
  clearValidation: () => elFormRef.value?.clearValidate(),
});
</script>

<style scoped>
.form-renderer {
  padding: 15px;
  border: 1px solid #eaeaea;
  background-color: #fff;
}
.rendered-table {
  border-collapse: collapse;
  width: 100%; /* Or based on col widths */
  table-layout: fixed;
  margin-bottom: 20px; /* For collections */
}
.rendered-table td {
  border: 1px solid #ebeef5;
  padding: 5px; /* Adjust padding for rendered form */
  /* vertical-align: top; default, can be overridden by cell.style.verticalAlign */
}
.form-data-item {
  border: 1px dashed #ccc;
  padding: 10px;
  margin-bottom: 15px;
}
.rendered-form-item {
  margin-bottom: 0; /* el-form-item has default margin, remove it if td padding is enough */
}
h3,
h4 {
  margin-top: 0;
  margin-bottom: 15px;
}
</style>
